﻿using Dora.Tools.Insurance.JT.Dto;
using Dora.Tools.Utility;
using Dora.Tools.Utility.Const.ApiSetting;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Xml;

namespace Dora.Tools.Insurance
{
    /// <summary>
    /// 江泰保险帮助类
    /// </summary>
    public class JTInsuranceHelper
    {
        private static readonly string Md5key = "3abc7b679437ba9a509b83b545d2afa1";
        /// <summary>
        /// 投保出单接口
        /// </summary>
        /// <param name="md5Key"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static ChinaTourinsResponseDto InsureOutOrder(string md5Key, InsureOrderRequestDto dto)
        {
            string str = JsonConvert.SerializeObject(dto);
            var doc = JsonConvert.DeserializeXmlNode(str);
            string xml = "<?xml version='1.0'?>" + doc.InnerXml.Replace("</insuredList><insuredList>",string.Empty);
            string confirmMessage = EncryptHelper.StringToHexChar(xml).ToLower();
            string md5sign = EncryptHelper.MD5Encrypt(md5Key + confirmMessage); 
            RestRequest request = new RestRequest("/bigCustomer/travelAccident/order", Method.POST);
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            var param = new
            {
                md5sign = md5sign,
                encoding = InsuranceConstValue.Encoding,
                confirmMessage = confirmMessage
            };
            request.AddObject(param);
            string content = RestHelper.ExecuteToString(InsuranceConstValue.JT_BaseUrl, request);  
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(content);
            ChinaTourinsResponseDto reqponseDto = ToResponseObject<ChinaTourinsResponseDto>(xmlDoc.InnerXml);
            return reqponseDto;
        }

        /// <summary>
        /// 撤保
        /// </summary>
        /// <param name="md5Key"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static CancelChinaTourinsResponseDto CancelInsureOutOrder(string md5Key, InsureOrderRequestDto dto)
        {
            string str = JsonConvert.SerializeObject(dto);
            var doc = JsonConvert.DeserializeXmlNode(str);
            string xml = "<?xml version='1.0'?>" + doc.InnerXml.Replace("</insuredList><insuredList>", string.Empty);
            string confirmMessage = EncryptHelper.StringToHexChar(xml).ToLower();
            string md5sign = EncryptHelper.MD5Encrypt(md5Key + confirmMessage);
            RestRequest request = new RestRequest("/bigCustomer/travelAccident/orderCancel", Method.POST);
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            var param = new
            {
                md5sign = md5sign,
                encoding = InsuranceConstValue.Encoding,
                confirmMessage = confirmMessage
            };
            request.AddObject(param);
            string content = RestHelper.ExecuteToString(InsuranceConstValue.JT_BaseUrl, request);
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(content);
            CancelChinaTourinsResponseDto reqponseDto = ToResponseObject<CancelChinaTourinsResponseDto>(xmlDoc.InnerXml);
            return reqponseDto;
        }

        /// <summary>
        /// 查询余额
        /// </summary>
        /// <param name="md5Key"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static QueryBlanceResponseDto QueryBlanceInsureOutOrder(string md5Key, QueryBlanceRequestDto dto)
        {
            string str = JsonConvert.SerializeObject(dto);
            var doc = JsonConvert.DeserializeXmlNode(str);
            string xml = "<?xml version='1.0'?>" + doc.InnerXml.Replace("</insuredList><insuredList>", string.Empty);
            string confirmMessage = EncryptHelper.StringToHexChar(xml).ToLower();
            string md5sign = EncryptHelper.MD5Encrypt(md5Key + confirmMessage);
            RestRequest request = new RestRequest("/BigCustomer/TravelAccident/QueryBlance", Method.POST);
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            var param = new
            {
                md5sign = md5sign,
                encoding = InsuranceConstValue.Encoding,
                confirmMessage = confirmMessage
            };
            request.AddObject(param);
            string content = RestHelper.ExecuteToString(InsuranceConstValue.JT_BaseUrl, request);
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(content);
            QueryBlanceResponseDto reqponseDto = ToResponseObject<QueryBlanceResponseDto>(xmlDoc.InnerXml);
            XmlNode root = xmlDoc.SelectSingleNode("//Data");
            if (root != null)
            {
                var blance = root.SelectSingleNode("blance").InnerText;
                reqponseDto.Data.blance = decimal.Parse(blance);
            }
            return reqponseDto;
        }

        /// <summary>
        /// 获取电子保单下载接口
        /// </summary>
        /// <returns></returns>
        public static string GetJTInsurePdf_Url(string serialNo,string travelCode)
        {
           return InsuranceConstValue.JT_BaseUrl + $"/bigCustomer/travelAccident/orderDown?serialNo={serialNo}&travelCode={travelCode}"; 
        }


        /// <summary>
        /// Convert xml message to object
        /// </summary>
        /// <param name="type"></param>
        /// <param name="xmlStr"></param>
        /// <returns></returns>
        public static T ToResponseObject<T>(string xmlStr) where T : new()
        {
            try
            {
                //T obj = default(T);
                T obj = new T();
                var repType = typeof(T);
                XmlDocument document = new XmlDocument();
                document.LoadXml(xmlStr);    //加载Xml文件  
                XmlElement node = document.DocumentElement; //xml的根标签
                var nodeList = document.ChildNodes;
                var properties = repType.GetProperties();

                foreach (var itemProp in properties)
                {
                    #region current type is List
                    if (itemProp.PropertyType.FullName.Contains("System.Collections.Generic.List"))
                    {

                        object array = new object();
                        var arryLength = 0;
                        var notNullLength = 0;
                        var arryType = itemProp.PropertyType.UnderlyingSystemType;

                        var objList = itemProp.GetValue(obj, null) as System.Collections.IEnumerable;
                        var enumt = objList.GetEnumerator();
                        //enumt.
                        var currentType = itemProp.PropertyType.GetGenericArguments()[0];

                        foreach (XmlNode xmlitem in node.ChildNodes)
                        {
                            if (xmlitem.Name == itemProp.Name)
                            {
                                arryLength++;
                            }
                        }
                        if (arryLength > 0)
                        {
                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
                            foreach (XmlNode item in node.ChildNodes)
                            {
                                //current type is array
                                if (item.Name == itemProp.Name)
                                {
                                    var model = currentType.Assembly.CreateInstance(currentType.FullName); // arryType.GetElementType().Assembly.CreateInstance(currentType.FullName);
                                    SetArray(item.ChildNodes, model, true);
                                    arrayModel.Add(model);
                                    //arrayModel[notNullLength] = model;
                                    notNullLength++;
                                }
                            }
                            itemProp.SetValue(obj, arrayModel, null);
                        }

                        continue;
                    }
                    #endregion

                    var baseType = itemProp.PropertyType.BaseType.Name;
                    if (baseType == "Array")
                    {
                        #region Current type is Array
                        object array = new object();
                        var arryLength = 0;
                        var notNullLength = 0;
                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
                        foreach (XmlNode xmlitem in node.ChildNodes)
                        {
                            if (xmlitem.Name == itemProp.Name)
                            {
                                arryLength++;
                            }
                        }
                        if (arryLength > 0)
                        {
                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
                            foreach (XmlNode item in node.ChildNodes)
                            {
                                //current type is array
                                if (item.Name == itemProp.Name)
                                {
                                    var model = arryType.GetElementType().Assembly.CreateInstance(arryType.GetElementType().FullName);
                                    SetArray(item.ChildNodes, model);
                                    arrayModel[notNullLength] = model;
                                    notNullLength++;
                                }
                            }
                            itemProp.SetValue(obj, arrayModel, null);
                        }
                        #endregion

                        continue;
                    }
                    else
                    {
                        #region Current type isn't Array
                        foreach (XmlNode item in node.ChildNodes)
                        {
                            #region Current type is Number
                            if (itemProp.Name == item.Name && (itemProp.PropertyType == typeof(long) || itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(string)))
                            {
                                if (itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(long))
                                {
                                    if (!string.IsNullOrEmpty(item.InnerText))
                                    {
                                        if (itemProp.PropertyType == typeof(int))
                                        {
                                            itemProp.SetValue(obj, Convert.ToInt32(item.InnerText), null);
                                        }
                                        else
                                        {
                                            itemProp.SetValue(obj, Convert.ToInt64(item.InnerText), null);
                                        }

                                    }
                                    else
                                    {
                                        itemProp.SetValue(obj, 0, null);
                                    }
                                }
                                else
                                {
                                    itemProp.SetValue(obj, item.InnerText, null);
                                }
                            }
                            #endregion

                            #region Current type is Model
                            if (itemProp.PropertyType != typeof(long) && itemProp.PropertyType != typeof(string) && itemProp.PropertyType != typeof(int) && itemProp.PropertyType.Name == item.Name && item.HasChildNodes && item.FirstChild.NodeType == System.Xml.XmlNodeType.Element)
                            {
                                var modelType = itemProp.PropertyType.UnderlyingSystemType;
                                var model = modelType.Assembly.CreateInstance(modelType.FullName);
                                SetArray(item.ChildNodes, model);
                                itemProp.SetValue(obj, model, null);
                            }
                            #endregion
                        }
                        #endregion

                        continue;
                    }
                }
                repType = obj.GetType();
                return obj;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private static Object SetArray(XmlNodeList xmlNodeList, object obj, bool isList = false)
        {
            try
            {
                var type = obj.GetType();
                var properties = type.GetProperties();
                foreach (var itemProp in properties)
                {
                    //if (isList)
                    if (itemProp.PropertyType.FullName.Contains("System.Collections.Generic.List"))
                    {
                        #region Current type is List
                        object array = new object();
                        var arryLength = 0;
                        var notNullLength = 0;
                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
                        var currentType = itemProp.PropertyType.GetGenericArguments()[0];
                        foreach (XmlNode xmlitem in xmlNodeList)
                        {
                            if (xmlitem.Name == itemProp.Name)
                            {
                                arryLength++;
                            }
                        }

                        if (arryLength > 0)
                        {
                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
                            foreach (XmlNode item in xmlNodeList)
                            {
                                //current type is array
                                if (item.Name == itemProp.Name)
                                {
                                    var model = currentType.Assembly.CreateInstance(currentType.FullName); // var model = arryType.GetElementType().Assembly.CreateInstance(arryType.GetElementType().FullName);
                                    SetArray(item.ChildNodes, model, true);
                                    arrayModel.Add(model);
                                    notNullLength++;

                                }
                            }
                            itemProp.SetValue(obj, arrayModel, null);
                        }
                        #endregion
                        return obj;
                    }


                    var baseType = itemProp.PropertyType.BaseType.Name;
                    if (baseType == "Array")
                    {
                        #region Current type is Array
                        object array = new object();
                        var arryLength = 0;
                        var notNullLength = 0;
                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
                        foreach (XmlNode xmlitem in xmlNodeList)
                        {
                            if (xmlitem.Name == itemProp.Name)
                            {
                                arryLength++;
                            }
                        }

                        if (arryLength > 0)
                        {
                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
                            foreach (XmlNode item in xmlNodeList)
                            {
                                //current type is array
                                if (item.Name == itemProp.Name)
                                {
                                    var model = arryType.GetElementType().Assembly.CreateInstance(arryType.GetElementType().FullName);
                                    SetArray(item.ChildNodes, model);
                                    arrayModel[notNullLength] = model;
                                    notNullLength++;

                                }
                            }
                            itemProp.SetValue(obj, arrayModel, null);
                        }
                        #endregion
                    }
                    else
                    {
                        foreach (XmlNode item in xmlNodeList)
                        {
                            #region Current type is Number
                            if (itemProp.Name == item.Name && (itemProp.PropertyType == typeof(long) || itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(string)))
                            {
                                if (itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(long))
                                {
                                    if (!string.IsNullOrEmpty(item.InnerText))
                                    {
                                        if (itemProp.PropertyType == typeof(int))
                                        {
                                            itemProp.SetValue(obj, Convert.ToInt32(item.InnerText), null);
                                        }
                                        else
                                        {
                                            itemProp.SetValue(obj, Convert.ToInt64(item.InnerText), null);
                                        }
                                    }
                                    else
                                    {
                                        itemProp.SetValue(obj, 0, null);
                                    }
                                }
                                else
                                {
                                    itemProp.SetValue(obj, item.InnerText, null);
                                }
                            }
                            #endregion

                            #region Current type is Model
                            if (itemProp.PropertyType != typeof(long) && itemProp.PropertyType != typeof(int) && itemProp.PropertyType != typeof(string) && itemProp.PropertyType.Name == item.Name && item.HasChildNodes && item.FirstChild.NodeType == System.Xml.XmlNodeType.Element)
                            {
                                var modelType = itemProp.PropertyType.UnderlyingSystemType;
                                var model = modelType.Assembly.CreateInstance(modelType.FullName);
                                SetArray(item.ChildNodes, model);
                                itemProp.SetValue(obj, model, null);
                            }
                            #endregion
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            return obj;
        }
    }
}
